#ifndef ADDRINFO_H_
#define ADDRINFO_H_

#include <winsock2.h>
#include <ws2tcpip.h>
#include <string>
#include <list>

typedef struct addrinfo_std_list
{
    int             ai_flags;
    int             ai_family;
    int             ai_socktype;
    int             ai_protocol;
    size_t          ai_addrlen;
    std::string     ai_canonname;
    struct sockaddr ai_addr_val;
} ADDRINFOA_STD_LIST, *PADDRINFOA_STD_LIST;

typedef struct addrinfoW_std_list
{
    int             ai_flags;
    int             ai_family;
    int             ai_socktype;
    int             ai_protocol;
    size_t          ai_addrlen;
    std::wstring    ai_canonname;
    struct sockaddr ai_addr_val;
} ADDRINFOW_STD_LIST, *PADDRINFOW_STD_LIST;

namespace boost {
namespace serialization {

template<class Archive>
void serialize(Archive & ar, ADDRINFOA_STD_LIST &g, const unsigned int version)
{
    ar & g.ai_flags;
    ar & g.ai_family;
    ar & g.ai_socktype;
    ar & g.ai_protocol;
    ar & g.ai_addrlen;
    ar & g.ai_canonname;
    ar & g.ai_addr_val;
}

template<class Archive>
void serialize(Archive & ar, ADDRINFOW_STD_LIST &g, const unsigned int version)
{
    ar & g.ai_flags;
    ar & g.ai_family;
    ar & g.ai_socktype;
    ar & g.ai_protocol;
    ar & g.ai_addrlen;
    ar & g.ai_canonname;
    ar & g.ai_addr_val;
}

} // namespace serialization
} // namespace boost


void ConvertToAddrinfoStdList (
    __in  const ADDRINFOA*                ai,
    __out std::list<ADDRINFOA_STD_LIST>&  ai_list
    );
void ConvertToAddrinfoStdList (
    __in  const ADDRINFOW*                ai,
    __out std::list<ADDRINFOW_STD_LIST>&  ai_list
    );

void CreateAddrinfoFromStdList ( 
    __in  std::list<ADDRINFOA_STD_LIST>  ai_list,
    __out ADDRINFOA**                    ai
    );
void CreateAddrinfoFromStdList ( 
    __in  std::list<ADDRINFOW_STD_LIST>  ai_list,
    __out ADDRINFOW**                    ai
    );

void DestroyAddrinfoFromStdList ( 
    __in ADDRINFOA*  ai
    );
void DestroyAddrinfoFromStdList ( 
    __in ADDRINFOW*  ai
    );

//////////////////////////////////////////////////////////////
//void ConvertToAddrinfoStdList (
//    __in  const ADDRINFOA*                ai,
//    __out std::list<ADDRINFOA_STD_LIST>&  ai_list
//    )
//{
//    const ADDRINFOA*   ai_ptr = ai;
//    ADDRINFO_STD_LIST  current;
//    
//    while (ai_ptr)
//    {
//        current.ai_flags = ai_ptr->ai_flags;
//        current.ai_family = ai_ptr->ai_family;
//        current.ai_socktype = ai_ptr->ai_socktype;
//        current.ai_protocol = ai_ptr->ai_protocol;
//        current.ai_addrlen = ai_ptr->ai_addrlen;
//        current.ai_canonname = 
//            (ai_ptr->ai_canonname == NULL) ? "" : ai_ptr->ai_canonname;
//        
//        if (ai_ptr->ai_addr)
//        {
//            current.ai_addr_val.sa_family = ai_ptr->ai_addr->sa_family;
//            strncpy_s (current.ai_addr_val.sa_data, 14, ai_ptr->ai_addr->sa_data, 14);
//        } else {
//            current.ai_addr_val.sa_family = -1;
//        }
//
//        ai_list.push_back(current);
//        ai_ptr = ai_ptr->ai_next;
//    }
//}
//
//////////////////////////////////////////////////////////////
//void CreateAddrinfoFromStdList ( 
//    __in  std::list<ADDRINFOA_STD_LIST>  ai_list,
//    __out ADDRINFOA**                    ai
//    )
//{
//    if (ai_list.size() == 0) {
//        *ai = NULL;
//        return;
//    }
//
//    ADDRINFOA*         ai_ptr = *ai;
//    ADDRINFO_STD_LIST* current;
//
//    do
//    {
//        current = &ai_list.front();
//        
//        ai_ptr->ai_flags = current->ai_flags;
//        ai_ptr->ai_family = current->ai_family;
//        ai_ptr->ai_socktype = current->ai_socktype;
//        ai_ptr->ai_protocol = current->ai_protocol;
//        ai_ptr->ai_addrlen = current->ai_addrlen;
//        if (current->ai_canonname == "")
//        {
//            ai_ptr->ai_canonname = NULL;
//        } else {
//            ai_ptr->ai_canonname = new char[current->ai_canonname.length()+1];
//            strcpy_s (ai_ptr->ai_canonname, current->ai_canonname.length()+1,
//                current->ai_canonname.c_str());
//        }
//        short tmp_cmp = current->ai_addr_val.sa_family;
//        if (tmp_cmp != -1)
//        {
//            ai_ptr->ai_addr = new SOCKADDR;
//            ai_ptr->ai_addr->sa_family = current->ai_addr_val.sa_family;
//            strncpy_s (ai_ptr->ai_addr->sa_data, 14, current->ai_addr_val.sa_data, 14);
//        } else {
//            ai_ptr->ai_addr = NULL;
//        }
//        if (ai_list.size() != 1) {
//            ai_ptr->ai_next = new ADDRINFOA;
//        } else {
//            ai_ptr->ai_next = NULL;
//        }
//
//        ai_ptr = ai_ptr->ai_next;
//        ai_list.pop_front();        
//    } while (!ai_list.empty());
//}
//
//////////////////////////////////////////////////////////////
//void DestroyAddrinfoFromStdList ( 
//    __in ADDRINFOA*  ai
//    )
//{
//    ADDRINFOA*  ai_ptr = ai;
//
//    if (ai == NULL) {
//        return;
//    }
//    
//    if (ai_ptr->ai_canonname != NULL)
//    {
//        delete[] ai_ptr->ai_canonname;
//    }
//    if (ai_ptr->ai_addr != NULL)
//    {
//        delete ai_ptr->ai_addr;
//    }
//    ai_ptr = ai_ptr->ai_next;
//    
//    while (ai_ptr)
//    {
//        if (ai_ptr->ai_canonname != NULL)
//        {
//            delete[] ai_ptr->ai_canonname;
//        }
//        if (ai_ptr->ai_addr != NULL)
//        {
//            delete ai_ptr->ai_addr;
//        }
//
//        ADDRINFOA* tmp = ai_ptr;
//        ai_ptr = ai_ptr->ai_next;
//        delete tmp;   
//    }
//    ai = NULL;
//}

#endif /* ADDRINFO_H_ */
